'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var _construct = _interopDefault(require('@babel/runtime-corejs2/helpers/construct'));
var _classCallCheck = _interopDefault(require('@babel/runtime-corejs2/helpers/classCallCheck'));
var _createClass = _interopDefault(require('@babel/runtime-corejs2/helpers/createClass'));
var EXIF = _interopDefault(require('@nuofe/exif-js'));
var _Promise = _interopDefault(require('@babel/runtime-corejs2/core-js/promise'));
var _regeneratorRuntime = _interopDefault(require('@babel/runtime-corejs2/regenerator'));
var _asyncToGenerator = _interopDefault(require('@babel/runtime-corejs2/helpers/asyncToGenerator'));
var _Object$keys = _interopDefault(require('@babel/runtime-corejs2/core-js/object/keys'));

var FILETYPE = "FILETYPE"; // 文件类型错误

var IMAGEERROR = "IMAGEERROR"; // 转换图片文件错误

var COMPRESSERROR = "COMPRESSERROR"; // 图片文件压缩错误

var UPLOADERROR = "UPLOADERROR"; // 图片上传出错

// 超时状态码
var STATIC_TIMEOUT = 502; // 上传响应失败

var STATIC_RESPONSE_ERROR = 999; // 上传文件异常

var STATIC_FILE_ERROR = 1000; // 图片压缩异常

var STATIC_COMPRESS_ERROR = 1001; // 图片转换异常

var STATIC_EXCHANGE_ERROR = 1002;

var createImage = (function (base64, callback) {
  return new _Promise(function (resolve, reject) {
    var image = new Image();

    image.onload = function () {
      resolve(image);
      image = null;
    }; // 图片加载出错


    image.onerror = function () {
      reject({
        message: "文件转换图片出错",
        errorType: IMAGEERROR,
        status: STATIC_EXCHANGE_ERROR
      });
    };

    image.src = base64;
  });
});

/**
 * 计算base64长度
 * @param {DataBase} base64
 */
var calcBASE64length = function calcBASE64length(base64) {
  return base64.length - base64.length / 8 * 2;
};

var defaultMaxQuality = 100; // 默认最小的压缩质量

var defaultMinQuality = 0; // 大图质量压成小图 差率 1kb ；比如规定最大2*1024*1024图片，3M的图片在向下压缩时允许最小2*1024*1024-1024
var CANVAS = document.createElement("canvas");
var CTX = CANVAS.getContext("2d");
/**
 * 压缩图片
 * @param {*} param0
 */

function imageTODataURL(_ref) {
  var img = _ref.img,
      quality = _ref.quality,
      fileType = _ref.fileType;
  var width = CANVAS.width = img.width;
  var height = CANVAS.height = img.height;
  CTX.clearRect(0, 0, width, height);
  CTX.drawImage(img, 0, 0, width, height);
  var base64 = CANVAS.toDataURL(fileType, quality / 100);
  CANVAS.width = 0;
  CANVAS.height = 0;
  return base64;
}
/**
 * 图片压缩算法
 * @param {*} param0
 */


var compressImage = function compressImage(_ref2) {
  var base64Image = _ref2.base64,
      maxSize = _ref2.maxSize,
      fileType = _ref2.fileType,
      defaultQuality = _ref2.quality;
  var compressBase64 = base64Image; // 最大的压缩率

  var compressMaxQuality = defaultMaxQuality; // 最小压缩率

  var compressMinQuality = defaultMinQuality; // 压缩得到最小的图片base64

  var minCompressBase = null;
  return new _Promise(function (resolve, reject) {
    var compressRecursion = function compressRecursion(_ref3) {
      var base64 = _ref3.base64,
          quality = _ref3.quality;

      try {
        createImage(base64).then(function (image) {
          // 将图片的类型统一转换 指定类型 默认 JPEG，
          compressBase64 = imageTODataURL({
            img: image,
            quality: quality,
            fileType: fileType
          });
          var compressSize = calcBASE64length(compressBase64);

          if (compressSize > maxSize) {
            compressMaxQuality = quality;
            var diffQuality = compressMaxQuality - compressMinQuality;

            if (diffQuality <= 2) {
              if (!minCompressBase) {
                // TODO: 上传图片大小限制较小时，存在一轮压缩无法达到目的.这是考虑等比例压缩图片而非质量压缩
                resolve({
                  result: true,
                  base64: compressBase64
                });
              } else {
                resolve({
                  result: true,
                  base64: minCompressBase || compressBase64
                });
              }
            } else {
              var compressQuality = Math.ceil((compressMaxQuality + compressMinQuality) / 2);
              compressRecursion({
                base64: compressBase64,
                quality: compressQuality
              });
            }
          } else {
            minCompressBase = base64;

            if (compressSize < maxSize) {
              compressMaxQuality = 2 * quality > 100 ? 100 : 2 * quality;
              compressMinQuality = quality;

              var _compressQuality = Math.ceil((compressMaxQuality + compressMinQuality) / 2);

              compressRecursion({
                base64: compressBase64,
                quality: _compressQuality
              });
            } else {
              resolve({
                result: true,
                base64: compressBase64
              });
            }
          }
        })["catch"](function (error) {
          reject({
            errorMsg: error,
            // 给开发者看的
            message: "图片压缩出错了",
            errorType: COMPRESSERROR,
            status: STATIC_COMPRESS_ERROR
          });
        });
      } catch (err) {
        reject({
          errorMsg: err,
          // 给开发者看的
          message: "图片压缩出错了",
          errorType: COMPRESSERROR,
          status: STATIC_COMPRESS_ERROR
        });
      }
    };

    compressRecursion({
      base64: base64Image,
      quality: defaultQuality
    });
  });
};

var Compress = /*#__PURE__*/
(function () {
  var _ref5 = _asyncToGenerator(
  /*#__PURE__*/
  _regeneratorRuntime.mark(function _callee(_ref4) {
    var base64, maxSize, fileType, size, maxQuality, minQuality, quality, compressBase64, _compressImage;

    return _regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            base64 = _ref4.base64, maxSize = _ref4.maxSize, fileType = _ref4.fileType;
            // 计算base64大小
            size = calcBASE64length(base64);

            if (!(size > maxSize)) {
              _context.next = 23;
              break;
            }

            // 执行压缩
            maxQuality = defaultMaxQuality;
            minQuality = defaultMinQuality;
            quality = Math.ceil((maxQuality + minQuality) / 2);
            _context.prev = 6;
            _context.next = 9;
            return compressImage({
              base64: base64,
              maxSize: maxSize,
              fileType: fileType,
              quality: quality
            });

          case 9:
            compressBase64 = _context.sent;

            if (!compressBase64.result) {
              _context.next = 15;
              break;
            }

            _compressImage = compressBase64.base64;
            return _context.abrupt("return", {
              result: true,
              base64: _compressImage
            });

          case 15:
            return _context.abrupt("return", {
              errorMsg: "代码错误",
              // 给开发者看的
              message: "图片压缩出错了",
              errorType: COMPRESSERROR,
              status: STATIC_COMPRESS_ERROR
            });

          case 16:
            _context.next = 21;
            break;

          case 18:
            _context.prev = 18;
            _context.t0 = _context["catch"](6);
            return _context.abrupt("return", {
              errorMsg: _context.t0,
              // 给开发者看的
              message: "图片压缩出错了",
              errorType: COMPRESSERROR,
              status: STATIC_COMPRESS_ERROR
            });

          case 21:
            _context.next = 24;
            break;

          case 23:
            return _context.abrupt("return", {
              result: true,
              base64: base64
            });

          case 24:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, null, [[6, 18]]);
  }));

  return function (_x) {
    return _ref5.apply(this, arguments);
  };
})();

var XHRUpload =
/*#__PURE__*/
function () {
  function XHRUpload(_ref) {
    var _ref$changeType = _ref.changeType,
        changeType = _ref$changeType === void 0 ? "image/jpeg" : _ref$changeType,
        _ref$base = _ref.base64,
        base64 = _ref$base === void 0 ? null : _ref$base,
        beforeUpload = _ref.beforeUpload,
        uploading = _ref.uploading,
        successUpload = _ref.successUpload,
        errorUpload = _ref.errorUpload,
        xhrParam = _ref.xhrParam,
        uploadUrl = _ref.uploadUrl,
        uploadTimeout = _ref.uploadTimeout,
        _ref$formdataName = _ref.formdataName,
        formdataName = _ref$formdataName === void 0 ? "file" : _ref$formdataName,
        _ref$fileName = _ref.fileName,
        fileName = _ref$fileName === void 0 ? 'blob' : _ref$fileName;

    _classCallCheck(this, XHRUpload);

    this.base64 = base64;
    this.beforeUpload = beforeUpload;
    this.uploading = uploading;
    this.successUpload = successUpload;
    this.errorUpload = errorUpload;
    this.changeType = changeType;
    this.uploadUrl = uploadUrl;
    this.uploadTimeout = uploadTimeout; // 上传的额外参数

    this.xhrParam = xhrParam;
    this.formdataName = formdataName;
    this.fileName = fileName;
    this.xhrUpload(base64);
  }

  _createClass(XHRUpload, [{
    key: "xhrUpload",
    value: function xhrUpload(dataBase64) {
      var _this = this;

      var xhr = new XMLHttpRequest();
      var formdata = this.getFormData();
      var blob = this.dataURLtoBlob(dataBase64);
      var filename = this.fileName;
      formdata.append(this.formdataName, blob, filename); // 这里是重写XHR 所以这个xhrParam必须是对象

      var xhrParam = this.xhrParam;

      if (xhrParam && xhrParam instanceof Object) {
        _Object$keys(this.xhrParam).map(function (keys) {
          formdata.append(keys, _this.xhrParam[keys]);
        });
      }

      if (xhrParam && !xhrParam instanceof Object) {
        console.error("xhrParam必须是对象");
        return;
      }

      var parDate = new Date() * 1;
      xhr.open("post", "".concat(this.uploadUrl, "?_=").concat(parDate));
      var timeout = this.uploadTimeout;
      var uploadTimer = setTimeout(function () {
        timeout = 0;
        xhr.abort(); // 请求中止
      }, timeout * 1000);

      xhr.onreadystatechange = function () {
        if (timeout <= 0) {
          _this.errorUpload({
            message: "上传超时",
            errorType: UPLOADERROR,
            status: STATIC_TIMEOUT
          });

          xhr.abort(); // 请求中止
        }

        if (Number(xhr.readyState) === 4) {
          clearTimeout(uploadTimer);

          try {
            var responseData = JSON.parse(xhr.responseText);
            _this.successUpload && _this.successUpload(responseData);
          } catch (err) {
            _this.errorUpload({
              message: "上传失败",
              errorType: UPLOADERROR,
              status: STATIC_RESPONSE_ERROR
            });
          }
        }
      };

      xhr.send(formdata);
    }
    /**
     * 把图片转成formdata 可以使用的数据...
     *这里要把\s替换掉..要不然atob的时候会出错....
     */

  }, {
    key: "dataURLtoBlob",
    value: function dataURLtoBlob(data) {
      var tmp = data.split(",");
      tmp[1] = tmp[1].replace(/\s/g, "");
      var binary = atob(tmp[1]);
      var array = [];

      for (var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
      }

      return this.getBlob(new Uint8Array(array), this.changeType);
    }
    /**
     * 获取blob对象的兼容性写法
     * @param buffer
     * @param format
     * @returns {*}
     */

  }, {
    key: "getBlob",
    value: function getBlob(data, datatype) {
      var _that = this;

      var result;

      try {
        if (datatype) {
          result = new Blob([data], {
            type: datatype
          });
        } else {
          result = new Blob(data);
        } // 一切正常,直接使用blob.

      } catch (e) {
        var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; // 使用blobbuilder来生成文件..

        if (e.name === "TypeError" && BlobBuilder) {
          var bob = new BlobBuilder();
          bob.append(data.buffer);
          result = bob.getBlob(datatype);
        } else {
          _that.errorUpload({
            message: "blob转换错误",
            errorType: BLOBCHANGEERROR,
            status: STATIC_EXCHANGE_ERROR
          });
        }
      }

      return result;
    }
    /**
     * 获取formdata
     */

  }, {
    key: "getFormData",
    value: function getFormData() {
      if (window.FormData) {
        return new window.FormData();
      } else {
        return this.formDataShim();
      }
    }
    /**
     * formdata 补丁, 给不支持formdata上传blob的android机打补丁
     * @constructor
     */

  }, {
    key: "formDataShim",
    value: function formDataShim() {
      var _this3 = this;

      var that = this;
      var parts = []; // Data to be sent

      var boundary = Array(5).join("-") + (+new Date() * (1e16 * Math.random())).toString(32);
      var oldSend = XMLHttpRequest.prototype.send; // 把xhr的send方法重写一下.

      XMLHttpRequest.prototype.send = function (xhrs) {
        var _this2 = this;

        // XMLHttpRequest调用send,传递 formDataShim返回值
        if (xhrs.isSelfFormdata === true) {
          var data = that.getBlob(that.parts);
          var fr = new FileReader();

          fr.onload = function () {
            oldSend.call(_this2, fr.result);
          };

          fr.onerror = function (err) {
            throw err;
          };

          fr.readAsArrayBuffer(data); // 设置content-type

          this.setRequestHeader("Content-Type", "multipart/form-data; boundary=".concat(boundary));
          XMLHttpRequest.prototype.send = oldSend;
        } else {
          oldSend.call(this, xhrs);
        }
      };

      return {
        append: function append(name, value, filename) {
          parts.push("\r\n--".concat(boundary, "\r\nContent-Disposition: form-data; name=\"").concat(name, "\""));

          if (value instanceof Blob) {
            parts.push("; filename=\"blob\"\r\nContent-Type: ".concat(value.type, "\r\n\r\n"));
            parts.push(value);
          } else {
            parts.push("\r\n\r\n".concat(value));
          }

          parts.push("\r\n"); // 最后加一下boundary..注意这里一定要在最后加\r\n..否则服务器有可能会解析参数失败..

          parts.push("\r\n--".concat(boundary, "--\r\n"));
          _this3.parts = parts;
        },
        isSelfFormdata: true
      };
    }
  }]);

  return XHRUpload;
}();

var XHRUpload$1 = (function () {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  return _construct(XHRUpload, args);
});

var defaultSize = 2 * 1024 * 1024; // 默认大小2M

/**
 * 给Function 类型的变量赋默认值
 * @param {Function} func
 * @param {*} type
 */

function defaultValue(func, type) {
  return func || function () {
    return undefined;
  };
}

var Upload =
/*#__PURE__*/
function () {
  function Upload(_ref) {
    var _this = this;

    var _ref$fileType = _ref.fileType,
        fileType = _ref$fileType === void 0 ? /\/(?:jpeg|png|gif|jpg)/i : _ref$fileType,
        _ref$changeType = _ref.changeType,
        changeType = _ref$changeType === void 0 ? "image/jpeg" : _ref$changeType,
        _ref$elem = _ref.elem,
        elem = _ref$elem === void 0 ? null : _ref$elem,
        _ref$base = _ref.base64,
        base64 = _ref$base === void 0 ? null : _ref$base,
        _ref$maxSize = _ref.maxSize,
        maxSize = _ref$maxSize === void 0 ? defaultSize : _ref$maxSize,
        _ref$multiple = _ref.multiple,
        multiple = _ref$multiple === void 0 ? false : _ref$multiple,
        beforeUpload = _ref.beforeUpload,
        uploading = _ref.uploading,
        successUpload = _ref.successUpload,
        errorUpload = _ref.errorUpload,
        xhrParam = _ref.xhrParam,
        uploadUrl = _ref.uploadUrl,
        _ref$uploadTimeout = _ref.uploadTimeout,
        uploadTimeout = _ref$uploadTimeout === void 0 ? 60 : _ref$uploadTimeout,
        _ref$formdataName = _ref.formdataName,
        formdataName = _ref$formdataName === void 0 ? 'file' : _ref$formdataName,
        _ref$fileName = _ref.fileName,
        fileName = _ref$fileName === void 0 ? 'blob' : _ref$fileName;

    _classCallCheck(this, Upload);

    this.elem = elem;
    this.maxSize = maxSize;
    this.base64 = base64;
    this.beforeUpload = beforeUpload;
    this.uploading = defaultValue(uploading);
    this.successUpload = defaultValue(successUpload);
    this.errorUpload = defaultValue(errorUpload);
    this.errorUpload = defaultValue(errorUpload);
    this.fileType = fileType;
    this.changeType = changeType;
    this.uploadUrl = uploadUrl;
    this.uploadTimeout = uploadTimeout;
    this.fileName = fileName; // 上传文件的 name

    this.formdataName = formdataName; // 上传的额外参数

    this.xhrParam = xhrParam; // 如果传入的是节点,需要调用init拿到将图片文件转为base64

    if (elem) {
      var fileList = elem.files;

      if (fileList && fileList.length) {
        var files = Array.prototype.slice.call(fileList); // TODO: 暂时支持单文件上传

        if (!multiple) {
          var file = files[0];

          if (this.beforeUpload && this.beforeUpload({
            file: file,
            type: "file",
            status: "getFile"
          }) === false) {
            // 用户传递了beforeUpload 如果返回false 直接中断
            return;
          } else {
            if (!fileType.test(file.type)) {
              this.errorUpload({
                message: '文件类型错误',
                errorType: FILETYPE,
                status: STATIC_FILE_ERROR
              });
              return false;
            }
          }

          this.init(file);
        }
      } else {
        this.errorUpload({
          message: '未获取到上传文件',
          errorType: FILETYPE,
          status: STATIC_FILE_ERROR
        });
      }
    } else if (this.base64) {
      // base64 图片无需获取方向信息，可直接执行压缩上传
      createImage(this.base64).then(function (image) {
        // 将图片的类型统一转换 指定类型 默认 JPEG，
        _this.changeImage(image);
      })["catch"](function (error) {
        _this.errorUpload({
          message: "创建base64文件失败",
          errorType: IMAGEERROR,
          status: STATIC_EXCHANGE_ERROR
        });
      });
    }
  }

  _createClass(Upload, [{
    key: "init",
    value: function init(imgFile) {
      var _that = this; // 获取照片方向角属性，用户旋转控制


      EXIF.getData(imgFile, function () {
        var Orientation = EXIF.getTag(this, "Orientation");
        _that.Orientation = Orientation;

        _that.getFileResult(imgFile);
      });
    }
  }, {
    key: "getFileResult",
    value: function getFileResult(imgFile) {
      var _this2 = this;

      var reader = new FileReader();
      reader.readAsDataURL(imgFile);

      reader.onload = function (eventFile) {
        var result = eventFile.target.result;
        createImage(result).then(function (image) {
          // 将图片的类型统一转换 指定类型 默认 JPEG，
          _this2.changeImage(image);
        })["catch"](function (error) {
          _this2.errorUpload({
            message: "blob转换错误",
            errorType: IMAGEERROR,
            status: STATIC_EXCHANGE_ERROR
          });
        });
      };
    }
  }, {
    key: "changeImage",
    value: function changeImage(image) {
      var _this3 = this;

      var canvas = document.createElement("canvas");
      var ctx = canvas.getContext("2d");
      var width = image.width,
          height = image.height;
      canvas.width = width;
      canvas.height = height;
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(image, 0, 0, width, height);

      if (this.Orientation) {
        // 如果方向角不为1，都需要进行旋转
        switch (this.Orientation) {
          case 6:
            // 需要顺时针（向左）90度旋转
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(1 * 90 * Math.PI / 180);
            ctx.drawImage(image, 0, -height, width, height);
            break;

          case 8:
            // 需要逆时针（向右）90度旋转
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(3 * 90 * Math.PI / 180);
            ctx.drawImage(image, -width, 0, width, height);
            break;

          case 3:
            // 需要180度旋转
            ctx.rotate(2 * 90 * Math.PI / 180);
            ctx.drawImage(image, -width, -height, width, height);
            break;

          default:
            ctx.drawImage(image, 0, 0, width, height);
            break;
        }
      }

      var nbase64 = canvas.toDataURL(this.changeType, 1);
      canvas.width = 0;
      canvas.height = 0; // 执行压缩

      Compress({
        base64: nbase64,
        maxSize: this.maxSize,
        fileType: this.changeType
      }).then(function (data) {
        // 压缩成功后对上传最后拦截
        if (data.result) {
          var base64 = data.base64;

          if (_this3.beforeUpload && _this3.beforeUpload({
            file: base64,
            type: "compress",
            status: 200
          }) === false) {
            return;
          }

          _this3.startUpload(base64);
        }
      })["catch"](function (error) {
        console.warn(error);

        _this3.errorUpload({
          message: "压缩失败",
          errorType: IMAGEERROR,
          status: STATIC_COMPRESS_ERROR
        });
      });
    }
  }, {
    key: "startUpload",
    value: function startUpload(base64) {
      var changeType = this.changeType,
          beforeUpload = this.beforeUpload,
          uploading = this.uploading,
          successUpload = this.successUpload,
          errorUpload = this.errorUpload,
          xhrParam = this.xhrParam,
          uploadUrl = this.uploadUrl,
          uploadTimeout = this.uploadTimeout,
          formdataName = this.formdataName,
          fileName = this.fileName;
      XHRUpload$1({
        base64: base64,
        changeType: changeType,
        beforeUpload: beforeUpload,
        uploading: uploading,
        successUpload: successUpload,
        errorUpload: errorUpload,
        xhrParam: xhrParam,
        uploadUrl: uploadUrl,
        uploadTimeout: uploadTimeout,
        formdataName: formdataName,
        fileName: fileName
      });
    }
  }]);

  return Upload;
}();
/**
 * @description 单图片上传集中处理
 * @property {String} uploadUrl 上传文件地址，必传
 * @property {RegExp} fileType 文件类型正则， default: /\/(?:jpeg|png|gif|jpg)/
 * @property {Object} elem example:{files:[file]} 文件域节点 target
 * @property {String} base64 图片base64
 * @property {Number} maxSize 文件size最大限制, default:2 * 1024 * 1024; // 默认大小2M
 * @property {Boolean} multiple 是否多文件 default:false, PS: 不支持多文件
 * @property {Object} xhrParam 上传额外参数
 * @property {String} fileName 上传文件名称 用于new FormDate() append方法第三个参数, default:'blob'
 * @property {String} formdataName 上传文件 name, default:'file'
 * @property {Number} uploadTimeout 执行上传接口时间 单位：s, default:60
 * @property {Function} beforeUpload 上传前调用函数 返回 false 阻止上传
 * @property {Function} uploading 调用上传接口时触发
 * @property {Function} successUpload 调用上传接口成功调用，直接返回接口响应报文JSON格式
 * @property {Function} errorUpload 上传失败回调  {status,errorType, message} 
 * @return ========= 失败详解 =====
 * @type status 502 接口上传超时， 999 响应失败， 1000 上传文件异常， 1001 图片压缩异常， 1002 图片转换异常
 * @type errorType 
 * @typw message 
 */


function YbsUpload() {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  return _construct(Upload, args);
}

module.exports = YbsUpload;
